package com.ib.client;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ib.domain.DeviceValue;
import com.ib.domain.TypeData;
import com.ib.handler.ClientHandler;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;

public class Client {

	private static final Logger LOG = LoggerFactory.getLogger(Client.class);

	private NioEventLoopGroup workGroup = new NioEventLoopGroup();
	private Channel channel;
	private Bootstrap bootstrap;
	
	private String ip = "192.168.1.31";
	private Integer port = 7777;
	private static String message = "{\"machineId\":\"362523450000933\",\"status\":\"1\",\"reqTime\":\"1524034538470\",\"version\":\"60000026\",\"sp\":\"46001\",\"longitude\":\"\",\"latitude\":\"\",\"cpu\":{\"rate\":\"0.53\",\"temperature\":\"58383\"},\"disk\":{\"total\":6592925696,\"surplus\":3790942208},\"ram\":{\"total\":\"935692 kB\",\"surplus\":\"57344 kB\"},\"serialPort\":{\"serial2\":\"1\"},\"net\":{\"type\":\"\",\"modal\":\"\",\"sign\":\"\"},\"scaleModel\":\"0\",\"ad\":[{\"play\":2,\"hb\":2,\"id\":\"397\",\"forUser\":\"1\"}]}";

	public static void main(String[] args) throws Exception {
		Client client = new Client();
		client.init();
		//client.sendData("{\"machineId\":\"423423\"}");
		//client.close();
		Thread.sleep(2000);
		client.sendData(message);
		Thread.sleep(100000);
		System.out.println("----------------");
		client.sendData("{\"machineId\":\"11111\"}");
	}

	public void init() {
		
		try {
			bootstrap = new Bootstrap();
		     //设置TCP协议的属性
	        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
	        bootstrap.option(ChannelOption.TCP_NODELAY, true);
			bootstrap.group(workGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
				protected void initChannel(SocketChannel socketChannel) throws Exception {
					ChannelPipeline p = socketChannel.pipeline();
					//p.addLast(new IdleStateHandler(0, 0, 5));
					// p.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, -4, 0));
					//p.addLast("ping", new IdleStateHandler(60, 20, 60 * 10, TimeUnit.SECONDS));
					p.addLast(new IdleStateHandler(0, 0, 20, TimeUnit.SECONDS));
					p.addLast(new StringDecoder());
					p.addLast(new StringEncoder());
					p.addLast(new ClientHandler(Client.this));
				}
			});
			doConnect();

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 重连机制,每隔2s重新连接一次服务器
	 */
	public void doConnect() {
		if (channel != null && channel.isActive()) {
			return;
		}

		ChannelFuture future = bootstrap.connect(ip, port);
		future.addListener(new ChannelFutureListener() {
			public void operationComplete(ChannelFuture futureListener) throws Exception {
				if (futureListener.isSuccess()) {
					channel = futureListener.channel();
					LOG.info("Connect to server successfully!");
					
				} else {
					LOG.info("Failed to connect to server, try connect after 2s");

					futureListener.channel().eventLoop().schedule(new Runnable() {
						public void run() {
							doConnect();
						}
					}, 2, TimeUnit.SECONDS);
				}
			}
		});
	}

	/**
	 * 发送数据 每隔2秒发送一次
	 * 
	 * @throws Exception
	 */
	public boolean sendData(String msg) throws Exception {
		boolean flag = false;
		int i = 1;
		while(i<=100) {
			if (channel != null && channel.isActive()) {
				LOG.info("client 发送数据: {}" , msg);
				channel.writeAndFlush(msg);
				flag = true;
				break;
			}else {
				LOG.info("The channel try send data {} times.",i);
			}
			Thread.sleep(2000);
			i++;
		}
		if(!flag) {
			LOG.error("The channel send data faild!");
		}
		return flag;
	}
	
	public void close() {
		if (channel != null && channel.isActive()) {
			channel.closeFuture();
			channel.close();
		}
	}

	/**
	 * 发送数据 每隔2秒发送一次
	 * 
	 * @throws Exception
	 */
	public void sendTestData() throws Exception {
		Random random = new Random(System.currentTimeMillis());
		for (int i = 0; i < 10000; i++) {
			if (channel != null && channel.isActive()) {

				DeviceValue deviceValue = new DeviceValue();
				deviceValue.setType(TypeData.CUSTOME);
				deviceValue.setAngle(i % 15);
				deviceValue.setSeatId(i % 30);
				deviceValue.setSpeed(i % 120);

				System.out.println("client 发送数据:" + deviceValue.toString());

				channel.writeAndFlush(deviceValue);
			}

			Thread.sleep(random.nextInt(20000));
		}
	}

}
